using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using Microsoft.Win32;

namespace TmxLib
{
    public static class SdkUtils
    {
        public static class Paths
        {

            public static string Root
            {
                get
                {
                    using (RegistryKey rk = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\.NETFramework"))
                    {
                        if (rk == null)
                            return null;

                        object rawPath = rk.GetValue(
                            string.Format(
                            "sdkInstallRootv{0}.{1}",
                            Environment.Version.Major,
                            Environment.Version.Minor));

                        string path = rawPath as string;
                        return path;
                    }
                }
            }

            public static string Bin
            {
                get
                {
                    return Root == null ? null : System.IO.Path.Combine(Root, "Bin");
                }
            }
        }

        static void CheckFolder(string fullName)
        {
            try { Directory.CreateDirectory(fullName); }
            catch {}
        }
        
        public static void BuildSattelite(string binFile, string rootNamespace, string culture, string projectFolder, string version, string[] localResources, string[] references)
        {
            string objLocal = "obj\\" + culture;
            string objFolder = Path.Combine(projectFolder, objLocal);
            CheckFolder(objFolder);
            

            Dictionary<string, string> resXmap = new Dictionary<string, string>();
            // Build resources
            {
                StringBuilder cmdBuilder = new StringBuilder();
                foreach (string s in localResources)
                {
                    string resKey = s;
                    if (s.ToLower().EndsWith("." + culture.ToLower() + ".resx"))
                        resKey = s.Substring(0, s.Length - culture.Length - 6);

                    string rName =
                        rootNamespace
                        + "." + resKey.Replace("\\", ".").Replace(" ", "_")
                        + "." + culture
                        + ".resources";

                    string rFile = objLocal + "\\" + rName;
                    resXmap[s] = rFile;
                    string part = s + "," + rFile;
                    cmdBuilder
                        .Append(cmdBuilder.Length > 0 ? " " : "")
                        .Append("\"")
                        .Append(part)
                        .Append("\"");
                }

                StringBuilder refs = new StringBuilder();
                foreach (string r in references)
                    refs.Append(refs.Length > 0 ? " " : "").Append("\"/r:").Append(r).Append("\"");

                string cmd = refs + " /usesourcepath /compile " + cmdBuilder;
                string exe = Path.Combine(SdkUtils.Paths.Bin, "resgen.exe");
                ProcessStartInfo si = new ProcessStartInfo(exe, cmd);
                si.UseShellExecute = false;
                si.ErrorDialog = false;
                si.CreateNoWindow = true;
                si.RedirectStandardError = true;
                si.WorkingDirectory = new DirectoryInfo(projectFolder).FullName;
                DumpCmd(si, culture);
                using (Process proc = Process.Start(si))
                {
                    proc.WaitForExit();
                    int exicCode = proc.ExitCode;
                    if (exicCode != 0)
                    {
                        using (StreamReader reader = proc.StandardError)
                        {
                            string errors = reader.ReadToEnd();
                            throw new AbandonedMutexException(
                                "ResGen failed with exit code "
                                + exicCode
                                + ". See Details below"
                                + Environment.NewLine
                                + errors);
                        }
                    }
                }
            }

            // build assembly
            {
                List<string> resources = new List<string>(resXmap.Values);
                string fw = Path.GetDirectoryName(typeof (int).Assembly.Location);
                string exe = Path.Combine(fw, "al.exe");
                StringBuilder cmdBuilder = new StringBuilder();
                foreach (string s in resources)
                {
                    cmdBuilder
                        .Append(cmdBuilder.Length > 0 ? " " : "")
                        .Append("\"/embed:")
                        .Append(s)
                        .Append("\"");
                }

                string output =
                    Path.Combine(
                        new FileInfo(binFile).DirectoryName,
                        culture + "\\" + Path.GetFileNameWithoutExtension(binFile) + ".resources.dll"
                        );

                string cmd = "/nologo /t:lib /culture:" + culture
                             + " \"/out:" + output + "\""
                             + " /version:" + version + " " + cmdBuilder;

                ProcessStartInfo si = new ProcessStartInfo(exe, cmd);
                si.UseShellExecute = false;
                si.ErrorDialog = false;
                si.CreateNoWindow = true;
                si.RedirectStandardOutput = true;
                si.WorkingDirectory = new DirectoryInfo(projectFolder).FullName;
                DumpCmd(si, culture);
                CheckFolder(Path.GetDirectoryName(output));
                using (Process proc = Process.Start(si))
                {
                    proc.WaitForExit();
                    int exicCode = proc.ExitCode;
                    if (exicCode != 0)
                    {
                        using (StreamReader reader = proc.StandardOutput)
                        {
                            string errors = reader.ReadToEnd();
                            throw new AbandonedMutexException(
                                "Failed to build sattelite '" + output + "' with exit code "
                                + exicCode
                                + ". See Details below"
                                + Environment.NewLine
                                + errors);
                        }
                    }
                }
            }
        }

        static void DumpCmd(ProcessStartInfo si, string culture)
        {
            string file =
                Path.Combine(si.WorkingDirectory, "call_" + Path.GetFileNameWithoutExtension(si.FileName) + "(" + culture + ").cmd");

            using (FileStream fs = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.Read))
            using (StreamWriter wr = new StreamWriter(fs, Encoding.Default))
                wr.WriteLine("\"" + si.FileName + "\"" + " " + si.Arguments);
        }

    }
}
